package com.glsc.ngateway.platform.service.cmdb;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.glsc.ngateway.common.api.common.enums.DictConstant;
import com.glsc.ngateway.common.base.domain.mysql.cmdb.*;
import com.glsc.ngateway.common.base.domain.mysql.gateway.platform.flow.cmdb.FlowFormDeviceStandardModify;
import com.glsc.ngateway.common.base.exception.PlatformException;
import com.glsc.ngateway.common.base.repo.mysql.cmdb.*;
import com.glsc.ngateway.common.base.repo.mysql.gateway.platform.flow.cmdb.FlowFormDeviceStandardModifyRepo;
import com.glsc.ngateway.platform.utils.AssertOverride;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

import static com.glsc.ngateway.common.api.common.enums.DictConstant.*;

@Service
public class CmdbDeviceStandardService {

    @Autowired
    private SequenceProductService sequenceProductService;
    @Autowired
    private CmdbDeviceStandardRepository cmdbDeviceStandardRepository;
    @Autowired
    private CmdbChangeLogRepository cmdbChangeLogRepository;
    @Autowired
    private CmdbCpuStandardDeviceStandardRelateRepository cmdbCpuStandardDeviceStandardRelateRepository;
    @Autowired
    private CmdbDiskStandardDeviceStandardRelateRepository cmdbDiskStandardDeviceStandardRelateRepository;
    @Autowired
    private CmdbMemoryStandardDeviceStandardRelateRepository cmdbMemoryStandardDeviceStandardRelateRepository;
    @Autowired
    private CmdbPartStandardDeviceStandardRelateRepository cmdbPartStandardDeviceStandardRelateRepository;
    @Autowired
    private FlowFormDeviceStandardModifyRepo flowFormDeviceStandardModifyRepo;


    public Object search(String type, Object paramsObj) {
        JSONObject objParmams = JSONObject.parseObject(JSONObject.toJSONString(paramsObj)).entrySet().stream()
                .filter(entry -> !entry.getValue().toString().isEmpty())
                .collect(JSONObject::new, (obj, entry) -> obj.put(entry.getKey(), entry.getValue()), JSONObject::putAll);

        if (StrUtil.isEmpty(objParmams.getString("orderByDirection"))){
            objParmams.put("orderByDirection","DESC");
        }
        if (StrUtil.isEmpty(objParmams.getString("orderByField"))){
            objParmams.put("orderByField","id");
        }
        Sort sort = Sort.by(Sort.Direction.fromString(objParmams.getString("orderByDirection")), objParmams.getString("orderByField"));

        Pageable pageable = PageRequest.of(objParmams.getInteger("pageNo")- 1, objParmams.getInteger("pageSize"),sort);

        if (CMDB_DEVICE_STANDARD.equals(type)){
            CmdbDeviceStandard paramSearchDto = JSONObject.parseObject(JSONObject.toJSONString(objParmams),CmdbDeviceStandard.class);
            Page<CmdbDeviceStandard> result = cmdbDeviceStandardRepository.searchByParam(pageable,paramSearchDto);
            return  result;
        }


        return null;
    }

    /**
     * @param cmdbDeviceStandard
     * @param account            操作人员
     * @param cmdbConfirm
     */
    @Transactional
    public CmdbDeviceStandard addOrUpdate(CmdbDeviceStandard cmdbDeviceStandard, String account, String cmdbConfirm) {
        int addOrUpdateFlag = 0;
        cmdbDeviceStandard.setIsDelete(NO_DELETE);
        CmdbChangeLog log = new CmdbChangeLog();
        if (cmdbDeviceStandard.getId() != null){
            //修改
            log.setChangeType(DictConstant.UPDATE_STRING);
            addOrUpdateFlag = 2;
        } else {
            //新增
            log.setChangeType(DictConstant.ADD_STRING);
            //自动生成编号
            String code = sequenceProductService.buildSequence(CMDB_DEVICE_STANDARD);
            cmdbDeviceStandard.setDeviceStandardCode(code);
            addOrUpdateFlag = 1;
        }
        //校验重复
        checkUnique(cmdbDeviceStandard,addOrUpdateFlag,cmdbConfirm);
        log.setChangeContent(JSONObject.toJSONString(cmdbDeviceStandard));
        log.setChangeFrom(CMDB_DEVICE_STANDARD);
        log.setChangeId(cmdbDeviceStandard.getId() != null ? cmdbDeviceStandard.getId().toString() : null);
        log.setChangeUser(account);
        cmdbChangeLogRepository.save(log);
        //关联修改
        if (addOrUpdateFlag == 1){
            //关联新增
            saveStandardRelate(cmdbDeviceStandard);
        } else {
            //关联修改
            //删除库里的数据
            cmdbCpuStandardDeviceStandardRelateRepository.updateIsDeleteByDeviceStandardCode(DELETED, cmdbDeviceStandard.getDeviceStandardCode());
            cmdbMemoryStandardDeviceStandardRelateRepository.updateIsDeleteByDeviceStandardCode(DELETED, cmdbDeviceStandard.getDeviceStandardCode());
            cmdbDiskStandardDeviceStandardRelateRepository.updateIsDeleteByDeviceStandardCode(DELETED, cmdbDeviceStandard.getDeviceStandardCode());
            cmdbPartStandardDeviceStandardRelateRepository.updateIsDeleteByDeviceStandardCode(DELETED, cmdbDeviceStandard.getDeviceStandardCode());
            saveStandardRelate(cmdbDeviceStandard);
        }
        return cmdbDeviceStandardRepository.save(cmdbDeviceStandard);
    }

    private void checkUnique(CmdbDeviceStandard cmdbDeviceStandard, int addOrUpdateFlag, String cmdbConfirm) {
        if (addOrUpdateFlag == 1){
            findSameName(cmdbDeviceStandard,cmdbConfirm);
//            findSamePartNum(cmdbDeviceStandard);
        } else {
            //修改情况，要把已有结果查询出来，如果有变化还要校验
            Optional<CmdbDeviceStandard> result = cmdbDeviceStandardRepository.findById(cmdbDeviceStandard.getId());
            if (result.isPresent()){
                if (! result.get().getStandardName().equals(cmdbDeviceStandard.getStandardName())){
                    if (result.get().getIsDelete().equals(NO_DELETE)){
                        findSameName(cmdbDeviceStandard,cmdbConfirm);
                    }
                }

//                if (! result.get().getPartNum().equals(cmdbDeviceStandard.getPartNum())){
//                    if (result.get().getIsDelete().equals(NO_DELETE)){
//                        findSamePartNum(cmdbDeviceStandard);
//                    }
//                }
                //修改情况存在未删除的记录
            } else {
                findSameName(cmdbDeviceStandard,cmdbConfirm);
//                findSamePartNum(cmdbDeviceStandard);
            }
        }
    }

    public void findSameName(CmdbDeviceStandard cmdbCpuStandard, String cmdbConfirm) {
        if (StrUtil.isNotEmpty(cmdbCpuStandard.getStandardName())) {
            List<CmdbDeviceStandard> result = cmdbDeviceStandardRepository.findAllByStandardNameAndIsDelete(cmdbCpuStandard.getStandardName(), NO_DELETE);
            if (CollectionUtil.isNotEmpty(result)) {
                throw PlatformException.errorWithOutMail("规格名称重复");
            }
            if (!StrUtil.equals(CMDB_CONFIRM,cmdbConfirm)){
                List<FlowFormDeviceStandardModify> flowForms = flowFormDeviceStandardModifyRepo.findFlowDeviceStandardName(cmdbCpuStandard.getStandardName());
                if (CollectionUtil.isNotEmpty(flowForms)){
                    throw PlatformException.errorWithOutMail("有发起过的流程"+flowForms.get(0).getProcessTitle()+"存在相同的设备规格名称");
                }
            }
        }
    }

//    private void findSamePartNum(CmdbCpuStandard cmdbCpuStandard) {
//        if (StrUtil.isNotEmpty(cmdbCpuStandard.getPartNum())){
//            List<CmdbCpuStandard> result = cmdbCpuStandardRepository.findAllByPartNumAndIsDelete(cmdbCpuStandard.getPartNum(), NO_DELETE);
//            if (CollectionUtil.isNotEmpty(result)){
//                throw PlatformException.errorWithOutMail("规格配件号重复");
//            }
//        }
//    }

    private void saveStandardRelate(CmdbDeviceStandard cmdbDeviceStandard) {

        if (StringUtils.isNotEmpty(cmdbDeviceStandard.getCpuStandardCode())) {
            AssertOverride.notNull(cmdbDeviceStandard.getCpuAmount(),"cpu数量不能为空");
            CmdbCpuStandardDeviceStandardRelate cpuStandardRelate = CmdbCpuStandardDeviceStandardRelate
                    .builder().cpuStandardCode(cmdbDeviceStandard.getCpuStandardCode())
                    .deviceStandardCode(cmdbDeviceStandard.getDeviceStandardCode())
                    .amount(cmdbDeviceStandard.getCpuAmount()).build();
            cmdbCpuStandardDeviceStandardRelateRepository.save(cpuStandardRelate);
        }
        if (StringUtils.isNotEmpty(cmdbDeviceStandard.getMemoryStandardCode())) {
            AssertOverride.notNull(cmdbDeviceStandard.getMemoryAmount(),"内存数量不能为空");
            CmdbMemoryStandardDeviceStandardRelate memoryStandardRelate = CmdbMemoryStandardDeviceStandardRelate
                    .builder().memoryStandardCode(cmdbDeviceStandard.getMemoryStandardCode())
                    .deviceStandardCode(cmdbDeviceStandard.getDeviceStandardCode())
                    .amount(cmdbDeviceStandard.getMemoryAmount()).build();
            cmdbMemoryStandardDeviceStandardRelateRepository.save(memoryStandardRelate);
        }
        if (CollectionUtil.isNotEmpty(cmdbDeviceStandard.getDiskStandardRelate())){
            List<CmdbDiskStandardDeviceStandardRelate> diskStandardRelate = cmdbDeviceStandard.getDiskStandardRelate();
            if (diskStandardRelate.stream().anyMatch(e -> e.getAmount() == null)){
                throw PlatformException.errorWithOutMail("硬盘数量不能为空");
            }
            diskStandardRelate.forEach(bean -> bean.setDeviceStandardCode(cmdbDeviceStandard.getDeviceStandardCode()));
            cmdbDiskStandardDeviceStandardRelateRepository.saveAll(diskStandardRelate);
        }
        if (CollectionUtil.isNotEmpty(cmdbDeviceStandard.getPartStandardRelate())){
            List<CmdbPartStandardDeviceStandardRelate> partStandardRelate = cmdbDeviceStandard.getPartStandardRelate();
            if (partStandardRelate.stream().anyMatch(e -> e.getAmount() == null)){
                throw PlatformException.errorWithOutMail("配件数量不能为空");
            }
            partStandardRelate.forEach(bean -> bean.setDeviceStandardCode(cmdbDeviceStandard.getDeviceStandardCode()));
            cmdbPartStandardDeviceStandardRelateRepository.saveAll(partStandardRelate);
        }

    }

    public void delete(CmdbDeviceStandard cmdbDeviceStandard, String account) {
        CmdbChangeLog log = new CmdbChangeLog();
        log.setChangeContent(JSONObject.toJSONString(cmdbDeviceStandard));
        log.setChangeFrom(CMDB_DEVICE_STANDARD);
        log.setChangeId(cmdbDeviceStandard.getId().toString());
        log.setChangeUser(account);
        log.setChangeType(DELETE_STRING);
        Optional<CmdbDeviceStandard> optional = cmdbDeviceStandardRepository.findById(cmdbDeviceStandard.getId().intValue());
        if (optional.isPresent()) {
            CmdbDeviceStandard bean = optional.get();
            bean.setIsDelete(DELETED);
            cmdbDeviceStandardRepository.save(bean);
            cmdbChangeLogRepository.save(log);
        } else {
            throw PlatformException.errorWithOutMail("删除记录不存在");
        }
    }

    public void deleteByCodeList(List<String> codes, String account) {
        CmdbChangeLog log = new CmdbChangeLog();
        log.setChangeContent(JSONObject.toJSONString(codes));
        log.setChangeFrom(CMDB_DEVICE_STANDARD);
        log.setChangeUser(account);
        log.setChangeType(DELETE_BATCH_STRING);
        cmdbChangeLogRepository.save(log);
        cmdbDeviceStandardRepository.updateIsDeleteByCodes(DELETED,codes);

    }


    public CmdbDeviceStandard findCmdbDeviceStandardByName(String name){
        if (StringUtils.isNotBlank(name)) {
            List<CmdbDeviceStandard> list = cmdbDeviceStandardRepository.findAll(Example.of(CmdbDeviceStandard.builder().standardName(name).build()));
            if (CollectionUtil.isNotEmpty(list)) {
                return list.get(0);
            }
        }
        return null;
    }

    public CmdbDeviceStandard findByDeviceStandardCode(String deviceStandardCode){
        AssertOverride.hasLength(deviceStandardCode,"设备规格号为空");
        CmdbDeviceStandard standard = cmdbDeviceStandardRepository.findOneByDeviceStandardCode(deviceStandardCode);
        //填充关联信息
        fillRelateInfo(standard);
        return standard;
    }

    /**
     * 填充关联信息
     * @param standard
     */
    private void fillRelateInfo(CmdbDeviceStandard standard) {
        String deviceStandardCode = standard.getDeviceStandardCode();
        //cpu关联
        CmdbCpuStandardDeviceStandardRelate cpuRelate = cmdbCpuStandardDeviceStandardRelateRepository.findOneByDeviceStandardCodeAndIsDelete(deviceStandardCode,NO_DELETE);
        if (cpuRelate != null && StringUtils.isNotEmpty(cpuRelate.getCpuStandardCode()) ){
            standard.setCpuStandardCode(cpuRelate.getCpuStandardCode());
//        CmdbCpuStandard cpu =  cmdbCpuStandardRepository.findOneByCpuStandardCode(cpuRelate.getCpuStandardCode());
            standard.setCpuStandardName(cpuRelate.getCmdbCpuStandard().getName());
            standard.setCpuAmount(cpuRelate.getAmount());
            standard.setCpuStandard(cpuRelate.getCmdbCpuStandard());
        }
        //内存关联
        CmdbMemoryStandardDeviceStandardRelate memoryRelate = cmdbMemoryStandardDeviceStandardRelateRepository.findOneByDeviceStandardCodeAndIsDelete(deviceStandardCode,NO_DELETE);
        if (memoryRelate != null && StringUtils.isNotEmpty(memoryRelate.getMemoryStandardCode())){
            standard.setMemoryStandardCode(memoryRelate.getMemoryStandardCode());
            standard.setMemoryStandardName(memoryRelate.getCmdbMemoryStandard().getName());
            standard.setMemoryAmount(memoryRelate.getAmount());
            standard.setMemoryStandard(memoryRelate.getCmdbMemoryStandard());
        }
        //硬盘关联
        List<CmdbDiskStandardDeviceStandardRelate> diskRelateList = cmdbDiskStandardDeviceStandardRelateRepository.findByDeviceStandardCodeAndIsDelete(deviceStandardCode,NO_DELETE);
        if (CollectionUtil.isNotEmpty(diskRelateList)){
            diskRelateList.stream().forEach(disk -> {disk.setDiskStandardName(disk.getCmdbDiskStandard().getName());});
        }
        standard.setDiskStandardRelate(diskRelateList);
        //配件关联
        List<CmdbPartStandardDeviceStandardRelate> partRelateList = cmdbPartStandardDeviceStandardRelateRepository.findByDeviceStandardCodeAndIsDelete(deviceStandardCode,NO_DELETE);
        if (CollectionUtil.isNotEmpty(partRelateList)){
            partRelateList.stream().forEach(part -> {
                part.setPartStandardName(part.getCmdbPartStandard().getName());
                part.setPartTypeName(part.getCmdbPartStandard().getCmdbPartType().getPartTypeName());
            });
        }
        standard.setPartStandardRelate(partRelateList);
    }

}